﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Globalization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

namespace TFMAPI
{
    /// <summary>
    /// Contains some helper functions
    /// </summary>
    public static class Helper
    {
        /// <summary>
        /// This method is a generic wrapper for getting the string response of a URL.
        /// It supports several types of resources, like http:// (the one we're using here) 
        /// but also ftp:// or file:// for example. Although the response must be only text.
        /// </summary>
        /// <param name="targetUrl"></param>
        /// <returns></returns>
        public static string GetUrlResponse(string targetUrl)
        {
            // Create the request
            WebRequest request = WebRequest.Create(targetUrl);
            // Get the response
            WebResponse response = request.GetResponse();
            // Open the stream for the response
            StreamReader reader = new StreamReader(response.GetResponseStream());
            // Read the contents
            string res = reader.ReadToEnd();
            // Close the open streams
            reader.Close();
            response.Close();
            // return result
            return res;
        }

        /// <summary>
        /// Generic extension method to deserialize JSON strings into specific helper objects.
        /// </summary>
        /// <typeparam name="T">The type used for deserialization</typeparam>
        /// <param name="json">The JSON string with the object definition</param>
        /// <returns>A deserialized object with the values defined in the JSON string</returns>
        /// <remarks>This methd extends the String class to add support for deserializing 
        /// from JSON when the string contains data in this format</remarks>
        public static T json2Object<T>(this string json)
        {
            MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json)); 
            DataContractJsonSerializer jsonSer = new DataContractJsonSerializer(typeof(T)); 
            T newObj = (T) jsonSer.ReadObject(ms); 
            ms.Close(); 
            return newObj;
        }

        /// <summary>
        /// This generic extension method serializes an object to a JSON string
        /// </summary>
        /// <param name="obj">An object to persists as JSON</param>
        /// <returns>The JSON representation of the object.</returns>
        public static string object2Json<T>(this T obj)
        {
            DataContractJsonSerializer ser = new DataContractJsonSerializer(obj.GetType()); 
            MemoryStream ms = new MemoryStream(); 
            ser.WriteObject(ms, obj); 
            string sJson = Encoding.UTF8.GetString(ms.ToArray()); 
            return sJson;
        }

        /// <summary>
        ///This method is used to convert the Twitter strings that represent dates to valid DateTime objects
        ///The string strings representing dates can not be converted directly through the default JSON deserialization into a DateTime because
        ///of the strange format Twitter uses for dates.
        /// </summary>
        /// <param name="twitterDate">A string in the twitter date/time representation format</param>
        /// <returns></returns>
        public static DateTime DateTimeFromTwitterDateString(string twitterDate)
        {
            return DateTime.ParseExact(twitterDate, "ddd MMM dd HH:mm:ss zzzz yyyy", CultureInfo.InvariantCulture);
        }

    }


#region Helper data object classses

    /// <summary>
    /// Class representing the information for a Twitter User.
    /// </summary>
    /// <remarks>Only the relevant fields for this application have been taken into account.
    /// The Twitter API returns several more fields that are not used here and therefore 
    /// have not been specified in the class below (ex:profile_sidebar_border_color, favourites_count...)</remarks>
    public class TwitterUserInfo
    {
        public string name { get; set; }
        public string location { get; set; }
        public string profile_image_url { get; set; }
        public string profile_image_url_full
        {
            get 
            {
                int pos = profile_image_url.LastIndexOf("_");
                int pos2 = profile_image_url.LastIndexOf(".");
                if (pos > 0)
                    return profile_image_url.Substring(0, pos) + profile_image_url.Substring(pos2);
                else
                    return profile_image_url;
            }
        }
        public string created_at { get; set; }
        //To get a valid DateTime from the Twitter DateTime (used several times in the helper classes)
        public DateTime createdAt 
        {
            get
            {
                return Helper.DateTimeFromTwitterDateString(this.created_at);
            }
        }
        public string url { get; set; }
        public long id { get; set; }
        public long followers_count { get; set; }
        public string lang { get; set; }
        public bool verified { get; set; }
        public string description { get; set; }
        public long friends_count { get; set; }
        public long statuses_count { get; set; }
        public string screen_name { get; set; }
        public StatusInfo status { get; set; }
        
        public class StatusInfo
        {
            public string created_at { get; set; }
            public DateTime createdAt
            {
                get
                {
                    return Helper.DateTimeFromTwitterDateString(this.created_at);
                }
            }
            public string text { get; set; }
            public string source { get; set; }
        }

        //Not part of the Twitter API
        public FollowersInfo Followers;
        public List<TwitterUserBasicInfo> FollowersHistory = new List<TwitterUserBasicInfo>();
        public long newFollowersCount = 0; //To keep the count of new followers for the account in each update
        public long lostFollowersCount = 0; //To keep the count of new or lost followers for the account in each update

        /// <summary>
        /// Serializes this object to a JSON String
        /// </summary>
        /// <returns>A string representing the current objet in JSON notation.</returns>
        /// <remarks>Uses the generic extension method object2Json in the Helper class</remarks>
        public string ToJson()
        {
            return this.object2Json<TwitterUserInfo>();
        }
    }


    /// <summary>
    /// Helper class to manage the information about the followers for a user
    /// It contains the ids of all the followers for a user.
    /// </summary>
    public class FollowersInfo
    {
        //Cursor information for paging on long lists of followers
        //This is used internally only, for the retrieval of paged info from Twitter
        //These properties are not serialized when ToJson is called because they are only needed internally
        public string next_cursor_str { get; set; }
        public string previous_cursor_str { get; set; }
        public long next_cursor { get; set; }
        public long previous_cursor { get; set; }

        //The full list of followers
        public System.Collections.Generic.List<long> ids { get; set; }

        /// <summary>
        /// Serializes this object to a JSON String
        /// </summary>
        /// <returns>A string representing the current objet in JSON notation.</returns>
        /// <remarks>Uses the generic extension method object2Json in the Helper class</remarks>
        public string ToJson()
        {
            return this.object2Json<FollowersInfo>();
        }
    }

    /// <summary>
    /// Helper class to get information about the quota available for making Twitter API calls.
    /// Used for checking the quota before making new calls, because, by default, it's only 150 API calls per hour by anonymous IP
    /// and the user can be using any other program that makes use of this quota.
    /// </summary>
    public class rate_limit_status
    {
        public int hourly_limit { get; set; }
        public string reset_time { get; set; }
        public DateTime resetTime
        {
            get
            {
                return Helper.DateTimeFromTwitterDateString(this.reset_time);
            }
        }
        public int remaining_hits { get; set; }
    }

    /// <summary>
    /// Basic information about a single follower.
    /// </summary>
    /// <remarks>
    /// This is used for followers tracking (lost or new ones).
    /// Saves the information that will be shown in the lists.
    /// The full information is always retrieved from the Twitter API in realtime, and updated here if newer
    /// </remarks>
    public class TwitterUserBasicInfo
    {

        //Needed for serialization
        public TwitterUserBasicInfo()
        { }

        //Creates an object instance copying the values from a pattern with the full information
        public TwitterUserBasicInfo(TwitterUserInfo pattern)
        {
            this.name = pattern.name;
            this.screenName = pattern.screen_name;
            this.photoUrl = pattern.profile_image_url;
            this.bio = pattern.description;
            this.numFollowers = pattern.followers_count;
            this.numFollowing = pattern.friends_count;
        }

        //The name and Lastname of the user
        public string name { get; set; }
        //The twitter username
        public string screenName { get; set; }
        //The 48x48 photo URL
        public string photoUrl { get; set; }
        // The user bio
        public string bio {get; set;}
        //Followers and Following count
        public long numFollowers { get; set; }
        public long numFollowing { get; set; }

        //If true indicates this was a new user added to the followers list. If is false is a dropped/lost follower detected
        public bool NewUser { get; set; }
        //the date of the event associated with this user
        public DateTime eventdate { get; set; }
    }

#endregion
}
